package com.hmdp.utils;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * Redis ID生成器
 * <p>
 * 基于Redis实现的全局唯一ID生成器，采用时间戳+自增序列号的方式生成ID。
 * 生成的ID具有全局唯一性、趋势递增性，适用于分布式系统中的订单号、业务ID等场景。
 * </p>
 * <p>
 * ID结构设计：
 * - 时间戳部分：占用高32位，记录从起始时间到当前时间的秒数
 * - 序列号部分：占用低32位，记录同一天内的自增序号
 * </p>
 */
@Component
public class RedisIdWorker {
    /**
     * 时间起始点 2025年1月1日 00:00:00 UTC
     * 作为时间戳计算的基准点，减少时间戳长度
     */
    private static final Long BEGIN_TIMESTAMP = 1735689600L;

    private StringRedisTemplate redisTemplate;

    public RedisIdWorker(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    private final static int COUNT_BITS = 32;

    /**
     * 生成全局唯一ID
     * <p>
     * 算法原理：
     * 1. 获取当前时间戳（秒级），减去起始时间戳作为高位部分
     * 2. 使用Redis的INCR命令生成当天的自增序列号作为低位部分
     * 3. 将高位部分左移32位，与低位部分进行位或运算组合成最终ID
     * </p>
     * 
     * @param keyPrefix Redis键前缀，用于区分不同业务场景的自增序列
     * @return 生成的全局唯一ID
     */
    public Long nextId(String keyPrefix) {
        // 计算时间戳部分 = 当前时间 - 起始时间
        LocalDateTime time = LocalDateTime.now();
        long nowSeconds = time.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSeconds - BEGIN_TIMESTAMP;
        
        // 生成序列号部分（按天自增）
        String date = time.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        Long increment = redisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
        
        // 组合时间戳和序列号生成最终ID
        // 高位32位存储时间戳，低位32位存储序列号
        return timestamp << COUNT_BITS | increment;
    }
}